package io.github.wppli.domain.pay.service;

import io.github.wppli.domain.pay.event.OrderBehaviorsEvent;
import io.github.wppli.domain.pay.model.entity.*;
import io.github.wppli.domain.pay.model.valobj.PayStatusVO;
import io.github.wppli.domain.pay.repository.IOrderRepository;
import io.github.wppli.domain.recommond.model.entity.UserBehaviorEntity;
import io.github.wppli.domain.recommond.model.valobj.UserProductBehaviorType;
import io.github.wppli.domain.recommond.repository.IProductRepository;
import io.github.wppli.types.event.BaseEvent;
import io.github.wppli.types.exception.AppException;
import io.github.wppli.types.snow.SnowflakeIdGenerator;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;


/**
 * 订单服务抽象类
 * @author li--jiaqiang 2025−03−19
 */
@Slf4j
@AllArgsConstructor
public abstract class AbstractOrderService implements IOrderService {

    protected final SnowflakeIdGenerator snowflakeIdGenerator;
    protected final IOrderRepository orderRepository;
    protected final IProductRepository productRepository;
    private final OrderBehaviorsEvent orderBehaviorsEvent;

    @Override
    @Transactional(rollbackFor = Exception.class, timeout = 350, propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
    public PayOrderEntity createOrder(ShopCartEntity shopCartEntity) {
        try {

            // todo 判断库存是否充足 - 使用责任链模式

            // -1 获取当前代理对象
            AbstractOrderService proxy = (AbstractOrderService) AopContext.currentProxy();

            // 0. 拿到userId和商品id
            Long userId = shopCartEntity.getUserId();
            Long productId = shopCartEntity.getProductId();

            // 1. 查询有效的未支付订单，如果存在直接返回 微信支付 Native CodeUrl
            /* <!-- queryUnpaidOrder 查询未支付订单 --> */
            UnpaidOrderEntity unpaidOrderEntity = orderRepository.queryUnpaidOrder(shopCartEntity);
            if (null != unpaidOrderEntity && PayStatusVO.WAIT.equals(unpaidOrderEntity.getPayStatus()) && null != unpaidOrderEntity.getPayUrl()) {
                log.info("创建订单-存在，已生成微信支付，返回 userId: {} orderId: {} payUrl: {}", userId, unpaidOrderEntity.getOrderId(), unpaidOrderEntity.getPayUrl());
                return PayOrderEntity.builder().userId(userId).orderId(unpaidOrderEntity.getOrderId()).payUrl(unpaidOrderEntity.getPayUrl()).payStatus(unpaidOrderEntity.getPayStatus()).build();
            } else if (null != unpaidOrderEntity && null == unpaidOrderEntity.getPayUrl()) {
                log.info("创建订单-存在，未生成微信支付 userId: {} orderId: {}", userId, unpaidOrderEntity.getOrderId());

                PayOrderEntity payOrderEntity = proxy.doPersonalPrepayOrder(userId, unpaidOrderEntity.getOrderId(), unpaidOrderEntity.getProductName(), unpaidOrderEntity.getTotalAmount().toString());
                if (payOrderEntity == null) {
                    log.error("创建订单-失败, 支付单生成失败");
                    throw new RuntimeException("创建订单-失败, 支付单生成失败");
                }
                log.info("创建订单-完成，生成支付单。openid: {} orderId: {} payUrl: {}", userId, payOrderEntity.getOrderId(), payOrderEntity.getPayUrl());
                return payOrderEntity;
            }
            log.info("创建订单-不存在有效的未支付订单，开始创建点单，返回 userId: {}", userId);
            // 2. 商品查询
            ProductEntity productEntity = productRepository.queryProduct(productId);
            log.info("商品: {}", productEntity.toString());
            if (!productEntity.isAvailable()) {
                throw new AppException("商品不可用");
            }

            // 3. 保存订单
            OrderEntity orderEntity = proxy.doSaveOrder(userId, productEntity);
            log.info("创建订单-订单保存成功, 未生成微信支付, 开始生成支付单，返回 openid: {} orderId: {}", userId, orderEntity.getOrderId());

            // 4. 创建支付单
            PayOrderEntity payOrderEntity = proxy.doPersonalPrepayOrder(userId, orderEntity.getOrderId(), productEntity.getProductName(), (orderEntity.getTotalAmount().multiply(new BigDecimal(shopCartEntity.getProductNum()))).toString());
            if (payOrderEntity == null) {
                log.error("创建订单-失败, 支付单生成失败...");
                throw new RuntimeException("创建订单-失败, 支付单生成失败...");
            }
            log.info("创建订单-完成，生成支付单。openid: {} orderId: {} payUrl: {}", userId, orderEntity.getOrderId(), payOrderEntity.getPayUrl());

            // todo 改成支付成功回调时触发 - 还有Task任务表
            sendOrderBehaviorsMessage(productEntity, userId);
            createBuyOrder(productEntity.getProductId(), shopCartEntity.getProductNum());

            return payOrderEntity;
        } catch (Exception e) {
            log.error("创建订单出错: ", e);
            log.error("创建订单-出错，已生成微信支付，返回 openid: {} productId: {}", shopCartEntity.getUserId(), shopCartEntity.getProductId());
            return null;
        }

    }

    private void sendOrderBehaviorsMessage(ProductEntity productEntity, Long userId) {
        OrderBehaviorsEvent.OrderBehaviorsEntity orderBehaviorsEntity = new OrderBehaviorsEvent.OrderBehaviorsEntity();
        orderBehaviorsEntity.setProductEntity(productEntity);
        UserBehaviorEntity userBehaviorEntity = UserBehaviorEntity.builder()
                .id(snowflakeIdGenerator.nextId())
                .userId(userId)
                .productId(productEntity.getProductId())
                .userBehaviorType(UserProductBehaviorType.BUY.getValue())
                .userBehaviorScore(UserProductBehaviorType.BUY.getWeight())
                .build();
        orderBehaviorsEntity.setUserBehaviorEntity(userBehaviorEntity);
        BaseEvent.EventMessage<OrderBehaviorsEvent.OrderBehaviorsEntity> orderBehaviorsEntityEventMessage = orderBehaviorsEvent.buildEventMessage(orderBehaviorsEntity);
        orderRepository.sendOrderBehaviorsMessage(orderBehaviorsEvent.topic(), orderBehaviorsEntityEventMessage);

    }


    protected abstract OrderEntity doSaveOrder(Long userId, ProductEntity productEntity);

    protected abstract PayOrderEntity doPersonalPrepayOrder(Long userId, String orderId, String productName, String amountTotal);

    protected abstract void createBuyOrder(Long productId, Integer count);
}